﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using System.IO;
using System.Xml;
using System.Text;
using System.Threading.Tasks;
using EAS_Protocol;
using EAS_Protocol.Models;
using EAS_Protocol.Helpers;
using System.Configuration;

namespace EASWebAccess.Controllers
{
    /// <summary>
    /// API for querying the Global Address List (GAL)    
    /// </summary>
    /// <remarks>
    /// The properties you can use in the query parameter are the following: 
    /// - First Name
    /// - Last Name
    /// - Display Name
    /// - Email Address (only complete addresses, not partials)
    /// - Office
    /// - Alias
    /// The following are not valid for searching: 
    /// - Title
    /// - Phone Number
    /// - Mobile Phone Number
    /// - Home Phone Number
    /// - Company
    /// </remarks>
    public class GALController : ApiController
    {
        
        /// <summary>
        /// <para>Queries the Global Address List (GAL) for entries.</para>
        /// <para> </para>
        /// <para>Note that the GAL is separate from the contacts of the individual users.</para>
        /// </summary>
        /// <param name="searchFor">The value to search for.</param>
        /// <param name="range">The range of results (starting from index 0) you are interested in. For example a value of 1 will give the range 0-1 meaning element 0 and 1 are returned (if there are multiple results.)</param>
        /// <param name="serverAddress">The address of the Exchange ActiveSync Server. Should be in the form "http(s)://FQDN"</param>
        /// <param name="credentials">Credentials for an EAS user. Format => base64(username:password).</param>
        /// <param name="DeviceID">The unique id of the "device".</param>
        /// <param name="DeviceType">The type of the "device".</param>
        /// <returns>List&lt;GALEntry&gt;. Returns HTTP 204 if no results found.</returns>        
        [HttpGet]
        [AllowAnonymous]
        [Route("api/GAL")]
        public IHttpActionResult queryGAL(string searchFor, int range, string serverAddress, string credentials, string DeviceID, string DeviceType)
        {                        
            List<GALEntry> galItems = new List<GALEntry>();

            string strUsername = HelperMethods.getUsername(credentials);
            //string strDeviceID = DeviceID;
            //string strDeviceType = DeviceType;            

            string easUrl = serverAddress;

            string ASVersion;
            string UserAgent;

            //Filter out necessary values from headers
            //Fall back to defaults if not provided
            //To do : Should defaults be provided or should the API throw an error?
            var headerValues = new List<string>().AsEnumerable();
            if (Request.Headers.TryGetValues("MS-ASProtocolVersion", out headerValues))
            {
                ASVersion = headerValues.First().ToString();
            }
            else
            {
                ASVersion = "14.1";
            }
            if (Request.Headers.TryGetValues("DeviceUserAgent", out headerValues))
            {
                UserAgent = headerValues.First().ToString();
            }
            else
            {
                UserAgent = "EASWeb";
            }

            Device dev = new Device();
            dev.ASVersion = ASVersion;
            dev.DeviceID = DeviceID;
            dev.DeviceType = DeviceType;
            dev.UserAgent = UserAgent;
            dev.Username = strUsername;
            dev.ServerAddress = easUrl;
            dev.Credentials = credentials;

            string searchResponse = AS_CMD.Search(dev, SearchTypes.SEARCH_GAL, searchFor, 0, range);

            try
            {
                var xmlGalEntry = new XmlDocument();
                xmlGalEntry.LoadXml(searchResponse);

                //Check the status of the search request
                var status = xmlGalEntry.GetElementsByTagName("Status");

                //Status of "1" == Success
                if (status[0].InnerXml == "1")
                {
                    //The "Total" tag will include the actual number of hits the search yielded
                    var totalResults = xmlGalEntry.GetElementsByTagName("Total");
                    string totalItems = totalResults[0].InnerXml;

                    //The "Result" tag will contain the number of entries as indicated by the "Range" parameter in the search request
                    var filteredResults = xmlGalEntry.GetElementsByTagName("Result");
                    int filteredItems = filteredResults.Count;

                    //int numberOfItems;
                    //Int32.TryParse(filteredItems, out numberOfItems);

                    for (int i = 0; i < filteredItems; i++)
                    {
                        galItems.Add(new GALEntry());

                        //A given GAL entry may have empty/null properties in AD
                        //These tags will not be included in the XML
                        //so we need to check the count for each xmlItem before adding the value.
                        var xmlItem = xmlGalEntry.GetElementsByTagName("DisplayName");
                        if (xmlItem.Count > 0)
                        {
                            galItems[i].DisplayName = xmlItem[i].InnerXml;
                        }

                        xmlItem = xmlGalEntry.GetElementsByTagName("Phone");
                        if (xmlItem.Count > 0)
                        {
                            galItems[i].Phone = xmlItem[i].InnerXml;
                        }

                        xmlItem = xmlGalEntry.GetElementsByTagName("Office");
                        if (xmlItem.Count > 0)
                        {
                            galItems[i].Office = xmlItem[i].InnerXml;
                        }

                        xmlItem = xmlGalEntry.GetElementsByTagName("Title");
                        if (xmlItem.Count > 0)
                        {
                            galItems[i].Title = xmlItem[i].InnerXml;
                        }

                        xmlItem = xmlGalEntry.GetElementsByTagName("Company");
                        if (xmlItem.Count > 0)
                        {
                            galItems[i].Company = xmlItem[i].InnerXml;
                        }

                        xmlItem = xmlGalEntry.GetElementsByTagName("Alias");
                        if (xmlItem.Count > 0)
                        {
                            galItems[i].Alias = xmlItem[i].InnerXml;
                        }

                        xmlItem = xmlGalEntry.GetElementsByTagName("FirstName");
                        if (xmlItem.Count > 0)
                        {
                            galItems[i].FirstName = xmlItem[i].InnerXml;
                        }

                        xmlItem = xmlGalEntry.GetElementsByTagName("LastName");
                        if (xmlItem.Count > 0)
                        {
                            galItems[i].LastName = xmlItem[i].InnerXml;
                        }

                        xmlItem = xmlGalEntry.GetElementsByTagName("HomePhone");
                        if (xmlItem.Count > 0)
                        {
                            galItems[i].HomePhone = xmlItem[i].InnerXml;
                        }

                        xmlItem = xmlGalEntry.GetElementsByTagName("MobilePhone");
                        if (xmlItem.Count > 0)
                        {
                            galItems[i].MobilePhone = xmlItem[i].InnerXml;
                        }

                        xmlItem = xmlGalEntry.GetElementsByTagName("EmailAddress");
                        if (xmlItem.Count > 0)
                        {
                            galItems[i].EmailAddress = xmlItem[i].InnerXml;
                        }

                        xmlItem = xmlGalEntry.GetElementsByTagName("Picture");
                        if (xmlItem.Count > 0)
                        {
                            galItems[i].Picture = xmlItem[i].InnerXml;
                        }

                        xmlItem = xmlGalEntry.GetElementsByTagName("Data");
                        if (xmlItem.Count > 0)
                        {
                            galItems[i].Data = xmlItem[i].InnerXml;
                        }
                    }
                }
                //Status !1 == !OK
                else
                {
                    //http://msdn.microsoft.com/en-us/library/gg675593(v=exchg.80).aspx
                    switch (status[0].InnerXml)
                    {
                        //Server error (returned from Exchange)
                        case "3":
                            return StatusCode(HttpStatusCode.BadRequest);                            

                        default:
                            return InternalServerError();
                            
                    }
                }
            }
            catch (Exception)
            {
                return InternalServerError();
            }

            if (galItems.Count == 0)
                return StatusCode(HttpStatusCode.NoContent);                
            else
                return Ok(galItems);
        }

    }
}
